package com.geostar.constructionland.index.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.geostar.constructionland.index.entity.AjaxResult;
import com.geostar.constructionland.index.entity.RateElement;
import com.geostar.constructionland.index.entity.RateExpression;
import com.geostar.constructionland.index.entity.model.*;
import com.geostar.constructionland.index.mapper.RateElementMapper;
import com.geostar.constructionland.index.mapper.RateExpressMapper;
import com.geostar.constructionland.index.service.RateService;
import com.geostar.constructionland.index.util.ComplexExpUtil;
import com.geostar.constructionland.index.util.FormatUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * @author yelll
 * @since 2020-3-18 15:04
 * 评分
 **/
@Controller
@RequestMapping("/rate")
@Api(tags = "指标评价相关接口")
@Slf4j
public class RateController {
    @Autowired
    RateElementMapper rateElementMapper;

    @Autowired
    RateService rateService;

    @ApiOperation("保存计算元素")
    @PostMapping("/saveRateElement")
    @ResponseBody
    public AjaxResult saveRateElement(@Valid RateElement rateElement){
        /**设置创建时间**/
        rateElement.setCreateTime(new Date());
        /**查看elecode是否重复**/
        List<RateElement> list = rateElementMapper.selectList(new QueryWrapper<RateElement>().eq("ele_code",rateElement.getEleCode()));
        if(list.size()>0){
            return new AjaxResult(500,"元素代码重复,请重新设置!");
        }
        rateElementMapper.insert(rateElement);
        return new AjaxResult(200,"指标元素保存成功!!");
    }

    @ApiOperation("更新计算元素")
    @PostMapping("/updateRateElement")
    @ResponseBody
    public AjaxResult updateRateElement(@Valid RateElement rateElement){
        /**设置创建时间**/
        rateElement.setCreateTime(new Date());
        /**查看elecode是否重复**/
        List<RateElement> list = rateElementMapper.selectList(new QueryWrapper<RateElement>().eq("ele_code",rateElement.getEleCode()));
        if(list.size()>0){
            return new AjaxResult(500,"元素代码重复,请重新设置!");
        }
        rateElementMapper.updateById(rateElement);
        return new AjaxResult(200,"更新成功!");
    }

    @ApiOperation("查询计算元素")
    @PostMapping("/getRateEles")
    @ResponseBody
    public IPage<RateElement> getRateEles(@Valid RateEleModel rateEleModel){
        Page<RateElement> page = new Page<>(rateEleModel.getPagenum(),rateEleModel.getPagesize());
        QueryWrapper<RateElement> queryWrapper = new QueryWrapper<RateElement>();
        if(rateEleModel.getDescription()!=null && !"".equals(rateEleModel.getDescription())){
            queryWrapper.like("description",rateEleModel.getDescription());
        }
        queryWrapper.orderByDesc("create_time");
        return rateElementMapper.selectPage(page,queryWrapper);
    }

    @ApiOperation("根据id查询计算元素")
    @PostMapping("/getRateEleById")
    @ResponseBody
    public RateElement getRateElement(@NotEmpty(message = "id不能为空") @RequestParam(name = "id")  String id){

        return rateElementMapper.selectById(id);
    }
    @ApiOperation("删除计算元素")
    @PostMapping("/delRateEle")
    @ResponseBody
    public AjaxResult delRateEle(@NotEmpty(message = "id不能为空") @RequestParam(name = "id")String id){
        rateElementMapper.deleteBatchIds(FormatUtils.getStringByList(id));
        return new AjaxResult(200,"删除成功!");
    }


    @Autowired
    RateExpressMapper rateExpressMapper;
    @ApiOperation("查询计算公式")
    @PostMapping("/getRateExpres")
    @ResponseBody
    public IPage<RateExpression> getRateExpressList(@Valid RateExpreModel rateExpreModel){
        Page<RateExpression> page = new Page<>(rateExpreModel.getPagenum(),rateExpreModel.getPagesize());
        QueryWrapper<RateExpression> queryWrapper = new QueryWrapper<RateExpression>();
        if(rateExpreModel.getDescription()!=null && !"".equals(rateExpreModel.getDescription())){
            queryWrapper.like("description",rateExpreModel.getDescription());
        }
        queryWrapper.orderByDesc("create_time");
        return rateExpressMapper.selectPage(page,queryWrapper);

    }
    @ApiOperation("删除计算公式")
    @PostMapping("/delRateExpre")
    public AjaxResult delRateExpress(@NotEmpty(message = "id不能为空") @RequestParam(name = "id")  String id){
        rateExpressMapper.deleteBatchIds(FormatUtils.getStringByList(id));
        return new AjaxResult(200,"删除成功!");
    }

    @ApiOperation("保存计算公式")
    @PostMapping("/saveRateExpression")
    @ResponseBody
    public AjaxResult saveRateExpression(@Valid RateExpression rateExpression){
        rateExpression.setCreateTime(new Date());
        rateExpressMapper.insert(rateExpression);
        return new AjaxResult(200,"计算表达式保存成功");
    }
    @ApiOperation("更新计算公式")
    @PostMapping("/updateRateExpression")
    @ResponseBody
    public AjaxResult updateRateExpression(@Valid RateExpression rateExpression){
        rateExpression.setCreateTime(new Date());
        rateExpressMapper.updateById(rateExpression);
        return new AjaxResult(200,"计算表达式修改成功");
    }

    @ApiOperation("计算元素得分")
    @PostMapping("/getScore")
    @ResponseBody
    public AjaxResult getScore(RateCalModel rateCalModel) {
        /**获取表达式中涉及的计算元素**/
        String[] rateEleIds =  rateCalModel.getRateExpId().split(",");
        QueryWrapper<RateElement> queryWrapper = new QueryWrapper<RateElement>();
        /**获取元素信息**/
        List<RateElement> rateElementList = rateElementMapper.selectList(queryWrapper.in("id",rateEleIds));
        List<Map>  resultPoints = new ArrayList<>();
        List<Future<Map>> futures = new ArrayList<>();
        /**分别计算得分**/
        for (RateElement rateElement : rateElementList) {
            Future<Map> future = rateService.getScoreTask(rateElement,rateCalModel);
            futures.add(future);
        }
        /**合并结果*/
        for (Future<Map> future : futures) {
            try {
                Map resultMap = future.get(30, TimeUnit.SECONDS);
               log.info("任务ID：" + resultMap.get("ID")+"完成；花费时间："+ resultMap.get("costTime")+"s");
                resultPoints.add(resultMap);
            }catch (Exception e){
                e.printStackTrace();
                continue;
            }
        }
        log.info("返回数据：{}",resultPoints);
        return AjaxResult.success(resultPoints);
    }

    @ApiOperation("计算评价分数")
    @PostMapping("/getRate")
    @ResponseBody
    public AjaxResult getRate(RateCalModel rateCalModel){
        //格式化区域
        String[] areas=rateCalModel.getAreas().split(",");
        /**获取表达式**/
        RateExpression rateExpression = rateExpressMapper.selectById(rateCalModel.getRateExpId());
        /**获取表达式中涉及的计算元素**/
        String[] rateEleCodes =  rateExpression.getRateEle().split(",");
        /**获取元素信息**/
        QueryWrapper<RateElement> queryWrapper = new QueryWrapper<RateElement>();
        List<RateElement> rateElementList = rateElementMapper.selectList(queryWrapper.in("ele_code",rateEleCodes));
        RateModel rateModel = new RateModel();
        rateModel.setEndTime(rateCalModel.getEndTime());
        rateModel.setStartTime(rateCalModel.getStartTime());
        rateModel.setRateExpression(rateExpression);
//        rateModel.setAreas(rateCalModel.getAreas());
        rateModel.setAreas(areas);
        rateModel.setRateElements(rateElementList);
        Map ratePoints = rateService.getRate(rateModel);
        return AjaxResult.success(ratePoints);
    }

    @ApiOperation("计算评价分数，计算总分")
    @PostMapping("/getRateByComplexExp")
    @ResponseBody
    public AjaxResult getRateByComplexExp(RateCalModel rateCalModel) throws Exception{
        //格式化区域
        String[] areas=rateCalModel.getAreas().split(",");
        /**格式化区域**/
        RateExpression rateExpression = rateExpressMapper.selectById(rateCalModel.getRateExpId());
        /**获取表达式中涉及的计算元素**/
        String[] rateExpressionIds =  rateExpression.getRateEle().split(",");
        /**获取涉及到的表达式**/
        QueryWrapper<RateExpression> queryWrapper = new QueryWrapper<>();
        List<RateExpression> expressionList = rateExpressMapper.selectList(queryWrapper.in("id",rateExpressionIds));
        RateEprModel rateEprModel = new RateEprModel();
        rateEprModel.setAreas(areas);
        rateEprModel.setEndTime(rateCalModel.getEndTime());
        rateEprModel.setStartTime(rateCalModel.getStartTime());
        rateEprModel.setRateExpression(rateExpression);
        rateEprModel.setRateExpressions(expressionList);
        Map ratePoints =  rateService.getCmpRate(rateEprModel);
        /**解析表达式**/
        return AjaxResult.success(ratePoints);
    }

    @ApiModelProperty("根据平差公式获取分数")
    @PostMapping("/getPointsByRemix")
    @ResponseBody
    public AjaxResult getPointsByRemix(RateCalModel rateCalModel) throws Exception{
        List<RateExpression> rateExpressions = new ArrayList<>();
        List<Map> list = new ArrayList<>();
        for(String area : rateCalModel.getAreas().split(",")){
            Map<String,Object> map = new HashMap<>();
            map.put("djs",area);
            list.add(map);
        }
        List<Future> futures = new ArrayList<>();
        String[] rateExps = rateCalModel.getRateExpId().split(",");

        String[] standSymbols = rateCalModel.getStandSymbols().split(",");
        List<String> standSymList = new ArrayList<>();
        for(int indexRate = 0 ; indexRate < rateExps.length ; indexRate++){
            String rateExpId = rateExps[indexRate];
            RateExpression rateExpression =
                    rateExpressMapper.selectOne(new QueryWrapper<RateExpression>().eq("id",rateExpId));
            if("total".equals(rateExpression.getType())){
                rateExpressions.add(rateExpression);
                continue;
            }
            standSymList.add(standSymbols[indexRate]);
            RateCalModel rateCalModel_new  = new RateCalModel();
            rateCalModel_new.setAreas(rateCalModel.getAreas());
            rateCalModel_new.setStartTime(rateCalModel.getStartTime());
            rateCalModel_new.setEndTime(rateCalModel.getEndTime());
            rateCalModel_new.setRateExpId(rateExpId);
            Future<Map> future = rateService.getCmpExps(rateCalModel_new);
            futures.add(future);
        }
        standSymbols = standSymList.toArray(new String[standSymList.size()]);
        for(int index = 0 ; index < futures.size() ; index++){
            String standSymob = standSymbols[index];
            Future<Map> future = futures.get(index);
            Map i = future.get(30,TimeUnit.SECONDS);
            Map<String,Double> ratePoints = (Map<String, Double>) i.get("ratePoints");
            List<Double> points = new ArrayList(ratePoints.values());
            /**获取最大值**/
            double maxPoints = points.stream().max(Comparator.naturalOrder()).get();
            /**获取最小值**/
            double minPoints = points.stream().min(Comparator.naturalOrder()).get();
            String rateExpId = (String)i.get("rateExpId");
            Set<String> xzqhs = ratePoints.keySet();
            for(String xzqh : xzqhs) {
                list.stream().filter(map -> map.get("djs").equals(xzqh)).forEach(map -> {
                    double ratePoint = ratePoints.get(xzqh);
                    map.put(rateExpId+"zsf",ratePoint);
                    if(standSymob.equals("1")){
                        double ratePointByRemix = ((ratePoint - minPoints)/(maxPoints-minPoints)) * 20 + 80;
                        if(ratePoint==minPoints){
                            ratePointByRemix = 80;
                        }else if(ratePoint == maxPoints){
                            ratePointByRemix = 100;
                        }
                        map.put(rateExpId, ratePointByRemix);
                    }else {
                        double ratePointByRemix = 100 - ((ratePoint - minPoints)/(maxPoints-minPoints)) * 20;
                        if(ratePoint==minPoints){
                            ratePointByRemix = 100;
                        }else if(ratePoint == maxPoints){
                            ratePointByRemix = 80;
                        }
                        map.put(rateExpId, ratePointByRemix);
                    }
                });
            }
            log.info("数据内容：{}",i);
            System.out.println("任务ID：" + i.get("rateExpId")+"完成；花费时间："+ i.get("costTime")+"s");
        }
        /***计算总值***/
        for(RateExpression rateExpression : rateExpressions){

            List<Double> evaluateList = new ArrayList<>();
            for(Map<String,Object> resultMap : list){
                /**获取计算公式**/
                String mathExpress = ComplexExpUtil.getTransedExpress(rateExpression.getMathExpression());
                JEP jep = new JEP();
                for(String rateId : resultMap.keySet()){
                    List<Map<String,String>> composeList = ComplexExpUtil.getComposeList(rateExpression.getMathExpression(),rateId);
                    log.info("元素：{},包含计算公式：{}",rateId,composeList);
                    if(composeList!=null){
                        Map resulstMap = ComplexExpUtil.getTransedValue(rateId,Double.valueOf(resultMap.get(rateId+"zsf").toString()),composeList);
                        String transedEle = ComplexExpUtil.getTransedEle(rateExpression.getMathExpression(),rateId);
                        jep.addVariable(transedEle,resulstMap.get("transedvalue"));
                    }
                }
                Node node = jep.parse(mathExpress);
                Double evaluate = Double.valueOf(jep.evaluate(node).toString());
                evaluateList.add(evaluate);
                resultMap.put(rateExpression.getId(),evaluate);
            }
            /**最大值、最小值*/
            double maxElv = evaluateList.stream().max(Comparator.naturalOrder()).get();
            double minElv = evaluateList.stream().min(Comparator.naturalOrder()).get();
            for(Map<String,Object> resultMap : list){
                double recValue = (Double)resultMap.get(rateExpression.getId());
                double initValue = 20*((recValue - minElv) / (maxElv - minElv)) + 80;
                if(recValue == maxElv){
                    initValue = 100;
                }else if(recValue == minElv){
                    initValue  = 80;
                }
                resultMap.put(rateExpression.getId(),initValue);
            }

        }
        return AjaxResult.success(list);
    }


    @ApiModelProperty("批量计算")
    @PostMapping("/getRatePointsByCplExps")
    @ResponseBody
    public AjaxResult getRatePointsByCompleExps(RateCalModel rateCalModel) throws Exception{
        List<RateExpression> rateExpressions = new ArrayList<>();
        List<Map> list = new ArrayList<>();
        for(String area : rateCalModel.getAreas().split(",")){
            Map<String,Object> map = new HashMap<>();
            map.put("djs",area);
            list.add(map);
        }
        List<Future> futures = new ArrayList<>();
        String[] rateExps = rateCalModel.getRateExpId().split(",");
        for(String rateExpId : rateExps){
            RateExpression rateExpression =
                    rateExpressMapper.selectOne(new QueryWrapper<RateExpression>().eq("id",rateExpId));
            if("total".equals(rateExpression.getType())){
                rateExpressions.add(rateExpression);
                continue;
            }
            RateCalModel rateCalModel_new  = new RateCalModel();
            rateCalModel_new.setAreas(rateCalModel.getAreas());
            rateCalModel_new.setStartTime(rateCalModel.getStartTime());
            rateCalModel_new.setEndTime(rateCalModel.getEndTime());
            rateCalModel_new.setRateExpId(rateExpId);
            Future<Map> future = rateService.getCmpExps(rateCalModel_new);
            futures.add(future);
        }
        for (Future<Map> future : futures) {
            while (true) {
                if (future.isDone() && !future.isCancelled()) {
                    Map i = future.get();
                    Map<String,Double> ratePoints = (Map<String, Double>) i.get("ratePoints");
                    String rateExpId = (String)i.get("rateExpId");
                    Set<String> xzqhs = ratePoints.keySet();
                    for(String xzqh : xzqhs) {
                        list.stream().filter(map -> map.get("djs").equals(xzqh)).forEach(map -> map.put(rateExpId,ratePoints.get(xzqh)));
                    }
                    log.info("数据内容：{}",i);
                    System.out.println("任务ID：" + i.get("rateExpId")+"完成；花费时间："+ i.get("costTime")+"s");
                    break;
                } else {
                    Thread.sleep(1);
                }
            }
        }

        /***计算总值***/
        for(RateExpression rateExpression : rateExpressions){
            for(Map<String,Object> resultMap : list){
                /**获取计算公式**/
                String mathExpress = ComplexExpUtil.getTransedExpress(rateExpression.getMathExpression());
                JEP jep = new JEP();
                for(String rateId : resultMap.keySet()){
                    List<Map<String,String>> composeList = ComplexExpUtil.getComposeList(rateExpression.getMathExpression(),rateId);
                    log.info("元素：{},包含计算公式：{}",rateId,composeList);
                    if(composeList!=null){
                        Map resulstMap = ComplexExpUtil.getTransedValue(rateId,Double.valueOf(resultMap.get(rateId).toString()),composeList);
                        String transedEle = ComplexExpUtil.getTransedEle(rateExpression.getMathExpression(),rateId);
                        jep.addVariable(transedEle,resulstMap.get("transedvalue"));
                    }
                }
                Node node = jep.parse(mathExpress);
                Object evaluate = jep.evaluate(node);
                resultMap.put(rateExpression.getId(),evaluate);
            }
        }
        return AjaxResult.success(list);
    }
}
